home *** CD-ROM | disk | FTP | other *** search
/ PC Shareware 1997 February / PC Shareware 1997-02.iso / programy / e! / api / beginend.pa_ / beginend.PAS
Encoding:
Pascal/Delphi Source File  |  1995-03-05  |  7.1 KB  |  257 lines

  1. {************************************************}
  2. {                         }
  3. { E! for Windows                 }
  4. { (c) - MainSoft sarl - 1992, 1994         }
  5. {                         }
  6. { Sample Extension DLL - version 2.0         }
  7. {                         }
  8. { This DLL implements an extension to the     }
  9. { Check Brace function. The original function     }
  10. { doesn't take into account the BEGIN/END,       }
  11. { CASE/END or REPEAT/UNTIL pairs of the Pascal     }
  12. { language. If loaded, this DLL will extend the  }
  13. { search and find the above matching pairs.     }
  14. {                         }
  15. {************************************************}
  16.  
  17. (*
  18. To use this DLL simply load it from the user menu or add its name to the
  19. list of autoloaded Extension DLLs by using the Autoload dialog box from
  20. the User Menu of EW. That's all. This extension cannot be executed because
  21. it only adds a hook to the CheckBrace function and exports no EWExecute
  22. function.
  23.  
  24. BEGINEND will check if the standard CheckBrace function failed and will try
  25. to find a BEGIN/END, CASE/END or REPEAT/UNTIL pair. BEGINEND will fail if the
  26. word at the cursor position doesn't belong to that list.
  27.  
  28. Once BEGINEND has been loaded, Ctrl H (default assignment) will trigger the
  29. CheckBrace function and pass along control to BEGINEND in case of failure.
  30.  
  31. BEGINEND works in both directions. If you set the cursor under BEGIN, CASE or
  32. REPEAT, it will search forward for END or UNTIL, otherwise if you set the
  33. cursor under UNTIL or END, it will look backward for a matching BEGIN, CASE
  34. or REPEAT.
  35.  
  36. Of course, nested pairs are ignored as well as keywords enclosed within
  37. comment braces.
  38.  
  39. BEGINEND uses the FuncExitHook provided by the EW API and some other API
  40. services giving information about the current Editor.
  41. *)
  42.  
  43. {$I compdir.inc}
  44. {$C MOVEABLE PRELOAD DISCARDABLE}
  45.  
  46. library BeginEnd;
  47.  
  48. uses WinTypes, EWApImp2, Strings;
  49.  
  50. {$I ewuser.inc}
  51.  
  52. var
  53.   SaveExit  : Pointer;
  54.   BufIndex,
  55.   LineIndex,
  56.   MaxIndex  : integer;
  57.   Len        : word;
  58.  
  59.  
  60. function SearchMatchingItem : boolean;
  61.  
  62. type
  63.   longrec = record
  64.     LoW, HiW : integer;
  65.   end;
  66.  
  67. const
  68.   MAXLEN = 255;
  69.  
  70. var
  71.   newch,
  72.   ch        : char;
  73.   CommentLevel    : integer;
  74.   PairCount    : word;
  75.   Linebuffer    : array[0..MAXLEN] of char;
  76.   bForward,
  77.   bDone     : boolean;
  78.  
  79.   function GetChar : char;
  80.  {-Retrieve characters from the text flow}
  81.   begin
  82.     if bForward then begin
  83.       Inc(BufIndex);
  84.       if BufIndex >= Len then begin
  85.     Inc(LineIndex);
  86.     if LineIndex <= MaxIndex then begin
  87.       while StrUpper(StrCopy(LineBuffer, EwGetLineAt(LineIndex)))[0] = #0 do begin
  88.         Inc(LineIndex);
  89.         if LineIndex > Maxindex then begin
  90.           GetChar := #0;
  91.           Exit;
  92.         end;
  93.       end;
  94.       Len := StrLen(LineBuffer);
  95.       BufIndex := 0;
  96.     end else begin
  97.       GetChar := #0;
  98.       Exit;
  99.     end;
  100.       end;
  101.     end else begin
  102.       Dec(BufIndex);
  103.       if BufIndex < 0 then begin
  104.     Dec(LineIndex);
  105.     if LineIndex >= 0 then begin
  106.       while StrUpper(StrCopy(LineBuffer, EwGetLineAt(LineIndex)))[0] = #0 do begin
  107.         Dec(LineIndex);
  108.         if LineIndex < 0 then begin
  109.           GetChar := #0;
  110.           Exit;
  111.         end;
  112.       end;
  113.       Len := StrLen(LineBuffer);
  114.       BufIndex := Pred(Len);
  115.     end else begin
  116.       GetChar := #0;
  117.       Exit;
  118.     end;
  119.       end;
  120.     end;
  121.     GetChar := LineBuffer[BufIndex];
  122.   end;
  123.  
  124.   function MatchPattern(ch : char) : boolean;
  125.  {-Verify if the word beginning at the cursor position match a list member}
  126.   var
  127.     MatchStr : array[0..6] of char;
  128.     MatchEnd : word;
  129.     P         : PChar;
  130.   const
  131.     Delimiters : set of char =
  132.       ['.', ' ', ',', ';', ':', '\', '/', '(', ')', '{', '}', '[', ']', '-'];
  133.   begin
  134.     MatchPattern := false;
  135.     if CommentLevel <> 0 then
  136.       Exit;
  137.     case ch of
  138.       'B' : StrCopy(MatchStr, 'BEGIN');
  139.       'R' : StrCopy(MatchStr, 'REPEAT');
  140.       'U' : StrCopy(MatchStr, 'UNTIL');
  141.       'C' : StrCopy(MatchStr, 'CASE');
  142.       'E' : StrCopy(MatchStr, 'END');
  143.     end;
  144.     MatchEnd := StrLen(MatchStr) + BufIndex;
  145.     P := StrPos(LineBuffer + BufIndex, MatchStr);
  146.     MatchPattern :=
  147.       (P <> nil)
  148.       and
  149.       (P - LineBuffer = BufIndex)
  150.       and
  151.       ((BufIndex = 0) or (LineBuffer[Pred(BufIndex)] in [' ', ';']))
  152.       and
  153.       ((MatchEnd = Len) or ((MatchEnd < Len) and (LineBuffer[MatchEnd] in Delimiters)));
  154.   end;
  155.  
  156. begin
  157.  {-Get current cursor position}
  158.   BufIndex := EWGetCaretPosX;
  159.   LineIndex := EWGetCaretPosY;
  160.  {-Get number of lines in current Editor}
  161.   MaxIndex := Pred(EWGetLineCount);
  162.  {-Get the current line}
  163.   StrUpper(StrCopy(LineBuffer, EwGetLineAt(LineIndex)));
  164.  {-Initialize search data}
  165.   Len := StrLen(LineBuffer);
  166.   CommentLevel := 0;
  167.   bDone := false;
  168.   bForward := Upcase(LineBuffer[BufIndex]) in ['B', 'C', 'R'];
  169.   if bForward then
  170.     Dec(BufIndex)
  171.   else
  172.     Inc(BufIndex);
  173.   SearchMatchingItem := false;
  174.   if not MatchPattern(GetChar) then
  175.     Exit
  176.   else
  177.     PairCount := 1;
  178.   repeat
  179.    {-Read character from text stream and update search variables}
  180.     ch := Upcase(GetChar);
  181.     case ch of
  182.       '{' : Inc(CommentLevel);
  183.       '}' : Dec(CommentLevel);
  184.       '(' : if bForward and (GetChar = '*') then
  185.           Inc(CommentLevel);
  186.       ')' : if not bForward and (GetChar = '*') then
  187.           Inc(CommentLevel);
  188.       '*' : begin
  189.           newch := GetChar;
  190.           if (bForward and (newch = ')')
  191.           or (not bForward and (newch = '('))) then
  192.         Dec(CommentLevel)
  193.         end;
  194.       'B',
  195.       'R',
  196.       'C' : if MatchPattern(ch) then
  197.           if bForward then
  198.         Inc(PairCount)
  199.           else
  200.         Dec(PairCount);
  201.       'U',
  202.       'E' : if MatchPattern(ch) then
  203.           if bForward then
  204.         Dec(PairCount)
  205.           else
  206.         Inc(PairCount);
  207.     end;
  208.     if PairCount = 0 then begin
  209.    {-Nesting level returned to 0. A matching sequence has been found}
  210.       SearchMatchingItem := true;
  211.       EWGotoXY(BufIndex, LineIndex);
  212.       bDone := true;
  213.     end;
  214.   until bDone or (ch = #0);
  215.  {-See comments in FunctionExitHook}
  216.   if not bDone then
  217.     EWWriteMessage('No matching sequence found')
  218.   else
  219.     EWWriteMessage(''); {-Clear previous error messages}
  220.   SearchMatchingItem := bDone;
  221. end;
  222.  
  223. function FuncExitHook(command : word; pRetCode : PInteger) : integer; export;
  224. {-Check whether the CheckBrace function succeeded.}
  225. { If not, call SearchMatchingItem}
  226. begin
  227.   FuncExitHook := 0;
  228.  {-Although the present version of the EW API doesn't check the return code}
  229.  { from the FuncExitHook functions, it is good practice to set this value  }
  230.  { to 0.}
  231.   if (command = ew_CheckBrace) and (pRetcode^ <> 0) then
  232.     if SearchMatchingItem then
  233.       pRetcode^ := 0 {-Success. Overwrite error code returned by CheckBrace}
  234.     else
  235.       pRetcode^ := ewerr_EXTFAILED; {-Unique exit code signaling that the}
  236.                     { extension function failed.}
  237.   {-You may also leave pRetcode^ unchanged and let EW display its usual }
  238.   { message. In that case EW would issue no message at all, so it's pre-}
  239.   { ferable to handle this ourselves.}
  240.  
  241. end;
  242.  
  243. procedure LibExit; far;
  244. begin
  245.   EWRemoveHook(EWHook_FunctionExit, @FuncExitHook);
  246.   ExitProc := SaveExit;
  247. end;
  248.  
  249. exports
  250.   FuncExitHook     index 1;
  251.  
  252. begin
  253.   EWSetHook(EWHook_FunctionExit, @FuncExitHook);
  254.   SaveExit := ExitProc;
  255.   ExitProc := @LibExit;
  256. end.
  257.